Add Jabber Agent

Matthew Werner 10 anni fa
parent
commit
d6ec02f45d
4 ha cambiato i file con 153 aggiunte e 0 eliminazioni
  1. 3 0
      Gemfile
  2. 4 0
      Gemfile.lock
  3. 65 0
      app/models/agents/jabber_agent.rb
  4. 81 0
      spec/models/agents/jabber_agent_spec.rb

+ 3 - 0
Gemfile

@@ -42,6 +42,9 @@ gem 'twitter-stream', :git => 'https://github.com/cantino/twitter-stream', :bran
42 42
 gem 'em-http-request'
43 43
 gem 'weibo_2'
44 44
 
45
+gem 'xmpp4r',   '~> 0.5.6'
46
+gem 'mustache', '~> 0.99.5'
47
+
45 48
 gem 'therubyracer'
46 49
 
47 50
 platforms :ruby_18 do

+ 4 - 0
Gemfile.lock

@@ -158,6 +158,7 @@ GEM
158 158
     multi_json (1.7.9)
159 159
     multi_xml (0.5.5)
160 160
     multipart-post (2.0.0)
161
+    mustache (0.99.5)
161 162
     mysql2 (0.3.13)
162 163
     naught (1.0.0)
163 164
     nokogiri (1.6.0)
@@ -302,6 +303,7 @@ GEM
302 303
       addressable
303 304
       httparty (> 0.6.0)
304 305
       json (> 1.4.0)
306
+    xmpp4r (0.5.6)
305 307
 
306 308
 PLATFORMS
307 309
   ruby
@@ -328,6 +330,7 @@ DEPENDENCIES
328 330
   jsonpath
329 331
   kaminari
330 332
   kramdown
333
+  mustache (~> 0.99.5)
331 334
   mysql2
332 335
   nokogiri
333 336
   pry
@@ -352,3 +355,4 @@ DEPENDENCIES
352 355
   webmock
353 356
   weibo_2
354 357
   wunderground
358
+  xmpp4r (~> 0.5.6)

+ 65 - 0
app/models/agents/jabber_agent.rb

@@ -0,0 +1,65 @@
1
+require 'mustache'
2
+module Agents
3
+  class JabberAgent < Agent
4
+    cannot_be_scheduled!
5
+    cannot_create_events!
6
+
7
+    description <<-MD
8
+      The JabberAgent will send any events it receives to your Jabber/XMPP IM account.
9
+
10
+      Specify the `jabber_server` and `jabber_port` for your Jabber server.
11
+
12
+      The `message` is sent from `jabber_sender` to `jaber_receiver`. This message
13
+      can contain any keys found in the source's payload, escaped using double curly braces.
14
+      ex: `"News Story: {{title}}: {{url}}"`
15
+    MD
16
+
17
+    def default_options
18
+      {
19
+        'jabber_server'   => '127.0.0.1',
20
+        'jabber_port'     => '5222',
21
+        'jabber_sender'   => 'huginn@localhost',
22
+        'jabber_receiver' => 'muninn@localhost',
23
+        'jabber_password' => '',
24
+        'message'         => 'It will be {{temp}} out tomorrow',
25
+        'expected_receive_period_in_days' => "2"
26
+      }
27
+    end
28
+
29
+    def working?
30
+      last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
31
+    end
32
+
33
+    def receive(incoming_events)
34
+      incoming_events.each do |event|
35
+        log "Sending IM to #{options['jabber_receiver']} with event #{event.id}"
36
+        deliver body(event)
37
+      end
38
+    end
39
+
40
+    def validate_options
41
+      errors.add(:base, "server and username is required") unless credentials_present?
42
+    end
43
+
44
+    def deliver(text)
45
+      client.send Jabber::Message::new(options['jabber_receiver'], text).set_type(:chat)
46
+    end
47
+
48
+    private
49
+
50
+    def client
51
+      Jabber::Client.new(Jabber::JID::new(options['jabber_sender'])).tap do |sender|
52
+        sender.connect(options['jabber_server'], (options['jabber_port'] || '5222'))
53
+        sender.auth(options['jabber_password'])
54
+      end
55
+    end
56
+
57
+    def credentials_present?
58
+      options['jabber_server'].present? && options['jabber_sender'].present? && options['jabber_receiver'].present?
59
+    end
60
+
61
+    def body(event)
62
+      Mustache.render(options['message'], event.payload)
63
+    end
64
+  end
65
+end

+ 81 - 0
spec/models/agents/jabber_agent_spec.rb

@@ -0,0 +1,81 @@
1
+require 'spec_helper'
2
+
3
+describe Agents::JabberAgent do
4
+  let(:sent) { [] }
5
+  let(:config) {
6
+    {
7
+      jabber_server: '127.0.0.1',
8
+      jabber_port: '5222',
9
+      jabber_sender: 'foo@localhost',
10
+      jabber_receiver: 'bar@localhost',
11
+      jabber_password: 'password',
12
+      message: 'Warning! {{title}} - {{url}}',
13
+      expected_receive_period_in_days: '2'
14
+    }
15
+  }
16
+
17
+  let(:agent) do
18
+    Agents::JabberAgent.new(name: 'Jabber Agent', options: config).tap do |a|
19
+      a.user = users(:bob)
20
+      a.save!
21
+    end
22
+  end
23
+
24
+  let(:event) do
25
+    Event.new.tap do |e|
26
+      e.agent = agents(:bob_weather_agent)
27
+      e.payload = { :title => 'Weather Alert!', :url => 'http://www.weather.com/' }
28
+      e.save!
29
+    end
30
+  end
31
+
32
+  before do
33
+    stub.any_instance_of(Agents::JabberAgent).deliver { |message| sent << message }
34
+  end
35
+
36
+  describe "#working?" do
37
+    it "checks if events have been received within the expected receive period" do
38
+      agent.should_not be_working # No events received
39
+      Agents::JabberAgent.async_receive agent.id, [event.id]
40
+      agent.reload.should be_working # Just received events
41
+      two_days_from_now = 2.days.from_now
42
+      stub(Time).now { two_days_from_now }
43
+      agent.reload.should_not be_working # More time has passed than the expected receive period without any new events
44
+    end
45
+  end
46
+
47
+  describe "validation" do
48
+    before do
49
+      agent.should be_valid
50
+    end
51
+
52
+    it "should validate presence of of jabber_server" do
53
+      agent.options[:jabber_server] = ""
54
+      agent.should_not be_valid
55
+    end
56
+
57
+    it "should validate presence of jabber_sender" do
58
+      agent.options[:jabber_sender] = ""
59
+      agent.should_not be_valid
60
+    end
61
+
62
+    it "should validate presence of jabber_receiver" do
63
+      agent.options[:jabber_receiver] = ""
64
+      agent.should_not be_valid
65
+    end
66
+  end
67
+
68
+  describe "receive" do
69
+    it "should send an IM for each event" do
70
+      event2 = Event.new.tap do |e|
71
+        e.agent = agents(:bob_weather_agent)
72
+        e.payload = { :title => 'Another Weather Alert!', :url => 'http://www.weather.com/we-are-screwed' }
73
+        e.save!
74
+      end
75
+
76
+      agent.receive([event, event2])
77
+      sent.should == [ 'Warning! Weather Alert! - http://www.weather.com/',
78
+                       'Warning! Another Weather Alert! - http://www.weather.com/we-are-screwed']
79
+    end
80
+  end
81
+end